/* 
 * File:   tcpSocket.cpp
 * Author: f10-kafedra
 * 
 * Created on 10 Сентябрь 2011 г., 15:34
 */

#include <QtCore/qtextcodec.h>
#include <QtGui/qmessagebox.h>

#include "tcpSocket.h"
#include "threads.h"

tcpSocket::tcpSocket(QString l, QString p) 
{
    reqCounter = 1;
    login = l;
    pass = p;
    inWork = false;
    configFiles.filled = false;
    singleRequest = false;
    host = (char*)HOST;
    connected = false;
    readed = false;
    sended = false;
    lastOperResult.result = 0;
    //this->setReadBufferSize(0);
    
    QFile f("request.txt");
    if (f.exists())
        f.remove();
    
    connect(this, SIGNAL(connected()), this, SLOT(slotConnected()), Qt::DirectConnection); 
    connect(this, SIGNAL(disconnected()), this, SLOT(slotDisConnected()), Qt::DirectConnection); 
    connect(this, SIGNAL(readyRead()), this, SLOT(slotReadBytes()), Qt::DirectConnection);
    
    log = new loglib();
    log->logOK("-----start logging------\n");
    //connectToHostBase(HOST, PORT);
    //request.operation = LOGIN;
    //loginToBase();
    
    //_connectToHostBase("192.168.9.120", 6666);
}

tcpSocket::~tcpSocket() {
    delete log;
    unloginFromBase();
}

int tcpSocket::_connectToHostBase(const char* host, const int port)
{
    if (peer_addr.set(PORT, HOST) == -1)
    {
#ifdef DEBUG_OUTPUT        
        cout << "ACE: error setting host:port" << endl;
#endif
        return -1;
    }
    else 
    if (connector.connect(peer, peer_addr) == -1)
    {
#ifdef DEBUG_OUTPUT
        cout << "ACE: connect unsuccessul" << endl;
#endif        
        return -1;
    }
#ifdef DEBUG_OUTPUT
    cout << "ACE: setting beginning cons complete" << endl;
    return 0;
#endif    
}


void tcpSocket::disconnectFromBase()
{
    connector.complete(peer, 0, &ACE_Time_Value::zero);
    peer.close();
}

bool tcpSocket::__sendData(string data)
{
    inWork = true;
    if (_connectToHostBase(host, PORT) == 0)
    {
        ssize_t lenTrans = 0;
        lenTrans = peer.send_n(data.c_str(), ACE_OS::strlen(data.c_str()), 0);
        data.clear();
        if (lenTrans > 0)
                return true;
        else
                return false;
    }
    
    data.clear();
    
    return false;
}

string tcpSocket::__reciveAnswer()
{
    ACE_Time_Value timeout(4);
    char buf[MAX_RECV_BUFFER_SIZE];
    //char* buf = (char*)malloc(MAX_RECV_BUFFER_SIZE);
    ssize_t lenRecv = 0;
    ssize_t amount = 0;
    size_t transf = 0;
    string str;
    while (lenRecv = peer.recv(buf, MAX_RECV_BUFFER_SIZE, &timeout))
    {
        amount += lenRecv;
//        ACE_OS::printf("%d:%d:%d\n", lenRecv, transf, amount);
        buf[lenRecv] = '\0';
        str.append(buf);
    }
    this->lastBuffer = QString::fromStdString(str);
    disconnectFromBase();
    inWork = false;
    return str;
}

int tcpSocket::connectToHostBase(QString host, int port)
{
    //cout << "try to connect" << endl;
    connectToHost(host, port);
    if (!waitForConnected(5000)) 
    {
#ifdef DEBUG_OUTPUT        
        cout << "Connect Unsuccessful" << endl;
#endif        
        return 1;
    }
    else
    {
#ifdef DEBUG_OUTPUT
        cout << "Connect to Host Base successful" << endl;
#endif
        return 0;
    }
}

void tcpSocket::slotConnected() {
#ifdef DEBUG_OUTPUT
    cout << "Connected!" << endl;
#endif    
    connected = true;
}

void tcpSocket::slotDisConnected()
{
#ifdef DEBUG_OUTPUT
    cout << "DisConnected!" << endl;
#endif
    connected = false;
}

void tcpSocket::slotReadBytes()
{
    readed = false;
    //cout << "slot read bytes: " << this->bytesAvailable() <<endl;
    //while (!this->atEnd())
    //while (this->waitForReadyRead(5000))
    while (this->bytesAvailable())
    {
        
//        while (!this->atEnd())
//        {

        //cout << "bytes for read available: " << this->bytesAvailable() << endl;
        //QByteArray buf = this->readAll();
        QByteArray buf = this->readAll();
        qint64 bytesReaded = buf.count();
        
        //cout << "try read" << endl;
        switch (apm)
        {
            case APM_REGUSER:
            {
                //QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
                this->lastBuffer.append(QString::fromAscii(tr(buf.data()).toAscii().data()));
                break;
            }
            case APM_INFO:
            {
                //QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));   
                this->lastBuffer.append(QString::fromAscii(tr(buf.data()).toAscii().data()));
                break;
            }
            case APM_REREG:
            {
                //cout << "*************************" << endl;
                //QTextCodec::setCodecForCStrings(QTextCodec::codecForName("cp1251"));
                //cout << QString::fromUtf8(buf.data()).toAscii().data() << endl;
                this->lastBuffer.append(QString::fromUtf8(buf.data()).toAscii().data());
                break;
            }
        }
#ifdef DEBUG_OUTPUT
        cout << "buffer readded = " << QString::number(bytesReaded).toAscii().data() << endl; 
#endif        
       //this->waitForReadyRead(5000);
        
    }
    
//    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("cp1251"));
    //cout << this->lastBuffer.toAscii().data() << endl;
//    if (this->waitForReadyRead(300))
//    {
        readed = true;
        inWork = false;
//    }
        
        //this->waitForReadyRead(2000);
}

void tcpSocket::sendData(QString data)
{
//    readed = false;
//    lastBuffer.clear();
        //    buffer.clear();
    cout << "sending data" << endl;
    inWork = true;
    if (_connectToHostBase(host, PORT) == 0)
    {
#ifdef DEBUG_OUTPUT
        cout << "ACE: trying send data" << endl;
#endif    
        iovec iov[1];
        iov[0].iov_base = data.toAscii().data();
        iov[0].iov_len = strlen(iov[0].iov_base);
cout << strlen(iov[0].iov_base)<< ": " << iov[0].iov_base << endl;

        ACE_Time_Value timeout(10);
        if (peer.sendv_n(iov, 1, &timeout) == -1)
        {
                cout << "not send" << endl;
        }
        else
            cout << "send!" << endl;
        //disconnectFromBase();
    }

    for (ssize_t n; (n = peer.recv(buf, sizeof buf)) > 0; )
        ACE::write_n (ACE_STDOUT, buf, n);
    

    
    
    disconnectFromBase();
        
    //inWork = false;
//    if (this->isOpen())
//    {
        //cout << "sending data" << endl;
//        log->logOK(data + '\n');
//        cout << "found I: " << data.indexOf("И") << endl;
        //data.replace(data.indexOf("И"), 2, "\u0418");
//        cout << "insending: \n" << data.toAscii().data() << endl;
//        write(data.toAscii().data());
//        if (waitForBytesWritten())
//        {
//            cout << "send successful" << endl;
//            sended = true;
 ///       }
//        else
 ///           cout << "sending failed" << endl;
    //}
}

void tcpSocket::loginToBase()
{
    reqCounter = 1;
    request.id = query.size() + 1;
    request.req = loginRequest("A", "C");
    request.operation = LOGIN;
    query.push_back(request);
    connected = true;
}

QString tcpSocket::loginRequest(QString codeCommand, QString codeAPM)
{
    QString request = codeCommand + '\n' + codeAPM + '\n' + codeCommand + '\n' 
                        + QString::number(MAGIC_USER_ID) + '\n' + QString::number(reqCounter++) + '\n' 
                        + login + '\n' + pass + "\n\n\n\n"
                        + login + '\n' + pass;
//    mainWindow.leLenRequest->setText(QString::number(request.length()));
    request.prepend(QString::number(request.length()) + '\n');
    return request;
}

QString tcpSocket::unLoginRequest(QString codeCommand, QString codeAPM)
{
    QString request = codeCommand + '\n' + codeAPM + '\n' + codeCommand + '\n' 
                        + QString::number(MAGIC_USER_ID) + '\n' + QString::number(reqCounter++) + '\n' 
                        + login + '\n' + pass + "\n\n\n\n"
                        + login;
//    mainWindow.leLenRequest->setText(QString::number(request.length()));
    request.prepend(QString::number(request.length()) + '\n');
    return request;
}

void tcpSocket::unloginFromBase()
{
    //connectToHostBase(HOST, PORT);
    request.id = query.size() + 1;
    request.req = unLoginRequest("B", "C");
    request.operation = UNLOGIN;
    query.push_back(request);      
    connected = false;
    //sendData(unLoginRequest("B", "C"));
}

void tcpSocket::getMaxMFN()
{
    //connectToHostBase(HOST, PORT);
    request.id = query.size() + 1;
    request.req = getMaxMFN_request("RDR");
    request.operation = GETMAXMFN;
    query.push_back(request);    
    //sendData(getMaxMFN_request("RDR"));
}

QString tcpSocket::getMaxMFN_request(QString bd)
{
    QString request = "O\nC\nO\n"
                        + QString::number(MAGIC_USER_ID) + '\n' + QString::number(reqCounter++) + '\n'
                        + "\n\n\n\n\n" + bd;
    
    request.prepend(QString::number(request.length()) + '\n');
//    cout << "request MFN: " << request.toAscii().data() << endl;
    return request;
}

void tcpSocket::getUser_MFN(QString MFN, QString maxMFN)
{
    cout << "Searching by MFN = " << MFN.toAscii().data() << endl;
    //connectToHostBase(HOST, PORT);
    //sendData(generalRequest("C", "C", "RDR\n" + QString::number(MFN) + "\n0"));
//    sendData(generalRequest("C", "C", "" + QString::number(MFN)));

//    while (MFN.length() < 6)
//        MFN.prepend('0');
    
    QString parametr;
    parametr = "RDR\n\n45\n1\nmpl,&UNIFOR('+0')\"\n1\n" + maxMFN + "!(if V30 : '" + MFN + "' then '1' else '0' fi)";
    sendData(generalRequestEditEnabled("K", "C", parametr));
    
}

QString tcpSocket::generalRequest(QString codeCommand, QString codeAPM, QString parameters)
{
    QString request = codeCommand + '\n' + codeAPM + '\n' + codeCommand + '\n'
                        + QString::number(MAGIC_USER_ID) + '\n' + QString::number(reqCounter++) 
                        + '\n' + "\n\n\n\n\n" + parameters;
    
    request.prepend(QString::number(request.length()) + '\n');
    
    //log->logOK(request);
    
    return request;
}

QString tcpSocket::generalRequestEditEnabled(QString codeCommand, QString codeAPM, QString parameters)
{
    QString request = codeCommand + '\n' + codeAPM + '\n' + codeCommand + '\n'
                        + QString::number(MAGIC_USER_ID) + '\n' + QString::number(reqCounter++) + '\n'
                        + login + '\n' + pass + '\n' + "\n\n\n" + parameters;
    
    request.prepend(QString::number(request.length()) + '\n');
    return request;
}

QString tcpSocket::generalRequestEditEnabled_0a(QString codeCommand, QString codeAPM, QString parameters)
{
    QString NL = QString::fromAscii(QByteArray::fromHex("0A").data());
    
    QString request = codeCommand + NL + codeAPM + NL + codeCommand + NL
                        + QString::number(MAGIC_USER_ID) + NL + QString::number(reqCounter++) + NL
                        + login + NL + pass + NL.repeated(4) + parameters;
    
    QFile f("request.txt");
    QTextStream outF(&f);
    if (f.open(QIODevice::Text | QIODevice::Append))
    {
        
        outF << "before:\n" << request;
    }
    
    request.prepend(QString::number(request.length()) + NL);

    //cout << request.toAscii().data() << endl;
    outF << "******\n\nafter:\n" << request;
        f.close();
    
    
    return request;
}

void tcpSocket::getServerVersion()
{
    //connectToHostBase(HOST, PORT);
    sendData(getSrvVersion());
}

QString tcpSocket::getSrvVersion()
{
    QString request = "1\nA\n1\n" + QString::number(MAGIC_USER_ID) + '\n' + QString::number(reqCounter++);
    
    request.prepend(QString::number(request.length()) + '\n');
    
    //log->logOK(request);
    
    return request;
}

void tcpSocket::getUser_FIO(QString FIO, QString maxMFN)
{
    
    maxMFN = "42857";
    //K\nC\nK\n123123\n4\nf10\nf10\n\n\n\nRDR\n\n45\n1\nmpl,&UNIFOR('+0')"\n1\n42719\n!(if V10 : 'Манукян' then '1' else '0' fi)
    
    cout << "Searching by FIO = " << FIO.toAscii().data() << endl;
    QStringList tmpList = FIO.split(" ", QString::SkipEmptyParts);
    int field = 10;
    QString parametr = "(if V" + QString::number(field++) + " : '";
    
    for (int i = 0; i<tmpList.count(); i++) // добавим уточнения в полях
    {
        parametr.append(tmpList.at(i));
        if ((tmpList.count() - (i+1)) > 0)
            parametr.append("' and V" + QString::number(field++) + " : '");
    }
    
    parametr.append("' then '1' else '0' fi)");
    parametr.prepend("RDR\n\n45\n1\nmpl,&UNIFOR('+0')'&&&&&'\"\n1\n" + maxMFN + "!");
   
    cout << parametr.toAscii().data() << endl;
//    sendData(generalRequestEditEnabled("K", "C", parametr));
    
    request.id = query.size() + 1;
    request.req = generalRequestEditEnabled("K", "C", parametr);
    request.operation = GET_USER_BY_FIO;
    query.push_back(request);       
    
}

void tcpSocket::updateUserInfo(QString MFN, QString maxMFN, QString fieldsToUpdate)
{
    cout << "Update record" << endl;
    QString updateRec = "RDR\n0\n1\n" + MFN + "#0";
    
    
    
    sendData(generalRequestEditEnabled("D", "C", updateRec));
}

void tcpSocket::createUser(QString maxMFN, QString userData)
{
    cout << "creating record" << endl;
//    QString element = QString::fromAscii(QByteArray::fromHex("1F1E").data());
    
/*    QString createRec = "RDR\n0\n1\n0#0" + element + "0#0" + element + 
                                     "10#Новый" + element +                     // Фамилиия
                                     "11#Пользователь" + element +              // имя
                                     "12#Системы" + element +                   // Отчество
                                     "21#2011" + element +                      // год рождения
                                     "50#Прочие" + element +                    // Категория
                                     "67#Пенсионеры" + element +                // доп. категория
                                     "51#^D20110915^Cф 10" + element +          // дата записи
                                     "52#^D20110916^Cф 10" + element +          // дата перерегистрации
                                     "17#319753" + element +                    // домашний телефон
                                     "32#f10 (собака) murmanlib.ru" + element + // мыло
                                     "14#^AНомер^BВыдан^SДатаВыдачи^CГород^DУлица^EНомерДома^HКвартира" + element +
                                     "13#^CГород^DУлица^EДом^HКвартира" + element + 
                                     "15#ИИЦ №10" + element +                  // место работы
                                     "16#Системный АДминистратор" + element +   // Должность
                                     "19#^AМестоУчебы^EКласс" + element +       // Место учебы
                                     "20#Высшее проф." + element +              // Образование
                                     "691#^DЕФ^F20110915^Eф 10" + element +     // читатель ЕФ \ СПС
                                     "33#^A20110915^Bф 10" + element +          // договор
                                     "31#^A20110915^BЧДА" + element +           // регистратор записи
                                     "920#RDR" + element;                      // Рабочий лист
*/
    request.id = query.size() + 1;
    request.req = generalRequestEditEnabled("D", "C", userData);
    request.operation = CREATE_USER;
    query.push_back(request);        
    //sendData(generalRequestEditEnabled("D", "C", userData));
}

void tcpSocket::getLastID()
{
    request.id = query.size() + 1;
    request.req = generalRequestEditEnabled("0", "C", "RDR");
    request.operation = GET_LOGIC_DEL;
    query.push_back(request);    
//    sendData(generalRequestEditEnabled("0", "C", "RDR"));
    //structRequest.lastRequest = GET_LOGIC_DEL;
}

void tcpSocket::getConfFile(QString file)
{
//    cout << "get config: " << file.toAscii().data() << endl;
//    cout << request.operation << endl;
    request.id = query.size() + 1;
    request.req = generalRequest("L", "C", "10.RDR." + file);
    query.push_back(request);    
//    sendData(generalRequest("L", "C", "10.RDR." + file));
    //structRequest.lastRequest = GET_FILE_CITY;
}

void tcpSocket::getOVD()
{
    request.id = query.size() + 1;
    request.req = generalRequestEditEnabled("H", "C", "RDR\nPOVD=\n1");
    query.push_back(request);    

    //sendData(generalRequestEditEnabled("H", "C", "RDR\nPOVD=\n1"));
    structRequest.lastRequest = GET_FILE_OVD;
}

void tcpSocket::checkIfUserExists(QStringList FIO)
{
    QString element = QString::fromAscii(QByteArray::fromHex("1F1E").data());
    
    request.id = query.size() + 1;
    request.req = generalRequestEditEnabled("G",
                                 "C",
                                 "RDR\nif val(ref(l('!'v21,v10,v11.6,v12.6),mfn))=val(mfn) then '0' else '2' fi/,\n-2\n0#0" + element + 
                                 "0#0" + element + "920#RDR" + element +
                                 "10#" + FIO.at(0) + element + "11#" + FIO.at(1) + element + "12#" + FIO.at(2) + element + "21#" + FIO.at(3) + element);
    request.operation = CHECK_USER_EXISTS;
    query.push_back(request);
}

void tcpSocket::getTargetAmount(QString target)
{
    //UCHETSPR..42.1.mpl,&UNIFOR('+0')'&&&&&'v2,'-',v3,'-',v4,'-',v5,'-',v6,'-',v7.1.96756.!(if V4 : '..............' then '1' else '0' fi)
    
    //structRequest.lastRequest = GET_TARGET_INFO;
    request.operation = GET_TARGET_INFO;
    request.id = query.size() + 1;
    request.req = generalRequestEditEnabled("K", "C", "UCHETSPR");
    query.push_back(request);    

    //sendData(generalRequestEditEnabled("H", "C", "RDR\nPOVD=\n1"));
}

void tcpSocket::getTarget(QString target, targetField field)
{
    request.operation = GET_TARGET_INFO;
    request.id = query.size() + 1;
    switch (field)
    {
        case TARGET_REQUEST:
        {
            request.req = generalRequestEditEnabled("K", "C", "UCHETSPR\nCEL=досуг\n42\n1\nmpl,&UNIFOR('+0')'&&&&&'");//v5,'%',v6,'%',v7");
            break;
        }
        case TYPE_INFO:
        {
            request.req = generalRequestEditEnabled("K", "C", "UCHETSPR\nTS=кодекс\n42\n1\nmpl,&UNIFOR('+2')'&&&'v5,'%',v6,'%',v7");
            break;
        }
    
    }
    query.push_back(request);    
}

void tcpSocket::getInfos(int from, int to)
{
    request.operation = GET_TARGET_INFO;
    request.id = query.size() + 1;
    request.req = generalRequestEditEnabled("G", "C", 
                                            "UCHETSPR\nmpl,&UNIFOR('+0')'&&&&&','target:'v4,'$','topic:',v5,'$','type:',v6,'$','source:',v7,'$','knowledge:',v11"
                                            "\n0\n" + QString::number(from) + "\n" + QString::number(to));
    query.push_back(request);
}

void tcpSocket::sendInfos(QStringList info)
{
    QString element = QString::fromAscii(QByteArray::fromHex("1F1E").data());
    QString reqs;

    reqs = "UCHETSPR\n0\n1\n0#0" + element + "0#0" + element + "920#UCHETSPR" + element +
            "2#" + info.at(0) + element +
            "3#" + info.at(1) + element +
            "4#" + info.at(2) + element +
            "5#" + info.at(3) + element +
            "6#" + info.at(4) + element;
    
    for (int i = 6; i < info.at(5).toInt() + 6; i++)
    {
        reqs.append("7#" + info.at(i) + element);
    }
    
    reqs.append("8#" + info.at(info.at(5).toInt() + 6) + element);
    
//    if (info.count() == info.at(5).toInt() + 8)
//    {
//        reqs.append("9#" + info.at(info.at(5).toInt() + 7) + element);
//    }

    if (info.size() == info.at(5).toInt() + 8)
        reqs.append("11#" + info.at(info.at(5).toInt() + 7) + element);

    request.operation = SEND_INFOS;
    request.id = query.size() + 1;
    request.req = generalRequestEditEnabled("D", "C", reqs);
    
    //                                          "11#" + info.at(info.at(5).toInt() + 8) + element);
    
    //cout << reqs.toAscii().data() << endl;
    
//    cout << "*****" << endl;
    query.push_back(request);
}

void tcpSocket::getUserByID(QString id)
{
    request.operation = GET_USER_BY_ID;
    request.id = query.size() + 1;
    request.req = generalRequestEditEnabled("K", "C", "RDR\n\"RI=" + id + "\"\n45\n1\nmpl,'&&&&&','10#',v10,'11#',v11,'12#',v12,'/',v40");
    query.push_back(request);
}

void tcpSocket::updateRecord(fields field, QString parametr, QString visit)
{
    cout << "send update records" << endl;
    
    QString element = QString::fromAscii(QByteArray::fromHex("1F1E").data());
    QString NL = QString::fromAscii(QByteArray::fromHex("0A").data());
    
    request.operation = UPDATE_RECORD;
    request.id = query.size() + 1;
    
    /*
             новое посещение в UTF-8
             старые данные в KOI8-R
     */
    QString req = generalRequest("D", "C", "RDR" + NL + "0" + NL + "1" + NL + parametr + QTextCodec::codecForName("UTF-8")->fromUnicode(visit) + QTextCodec::codecForName("UTF-8")->fromUnicode(element));
    //QString req = generalRequest("D", "C", "RDR" + NL + "0" + NL + "1" + NL + QTextCodec::codecForName("cp1251")->fromUnicode(parametr) + QTextCodec::codecForName("UTF-8")->fromUnicode(visit) + QTextCodec::codecForName("UTF-8")->fromUnicode(element));
    request.req = req;//generalRequestEditEnabled("D", "C", "RDR" + NL + "0" + NL + "1" + NL + parametr + visit + element);
//    printf("%s\n", str.c_str());
    
//        for (int i = 727; i < 729; i++)
//        {
//            cout << req.at(i).toAscii();
//        }
//        cout << endl;
//    }
    
//    QFile f("request.txt");
//    if (f.open(QIODevice::Text | QIODevice::WriteOnly))
//    {
//        QTextStream outF(&f);
//        outF << request.req;
//        f.close();
//    }
 
//    cout << request.req.toAscii().data() << endl;
    query.push_back(request);
//    lastOperResult.result = 1;
}

void tcpSocket::getUserRecord(QString mfn)
{
    request.operation = GET_RECORD;
    request.id = query.size() + 1;
    request.req = generalRequest("C", "C", "RDR\n" + mfn + "\n0\n\n");
    
    //cout << "request: \n" << request.req.toAscii().data() << endl;
    
    query.push_back(request);
}

void tcpSocket::unlockRecord(QString mfn)
{
    request.operation = GET_RECORD;
    request.id = query.size() + 1;
    request.req = generalRequest("Q", "A", "RDR\n" + mfn);
    query.push_back(request);
}